﻿#include "MonitorInfo.h"
#include <QGuiApplication>
#include <QScreen>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#include <QByteArray>
#include <QTransform>
#include <QDebug>


// 解析 EDID 中的制造商 ID
static QString parseManufacturer(const BYTE *edid)
{
    char manufacturer[4] = {0};
    manufacturer[0] = ((edid[8] & 0x7C) >> 2) + 'A' - 1;
    manufacturer[1] = (((edid[8] & 0x03) << 3) | ((edid[9] & 0xE0) >> 5)) + 'A' - 1;
    manufacturer[2] = (edid[9] & 0x1F) + 'A' - 1;
    return QString::fromLatin1(manufacturer);
}

// 解析 EDID 中的显示器名称
static QString parseModelName(const BYTE *edid)
{
    // EDID 的显示器名称通常在 0x36 - 0x48 之间的 ASCII 字符
    // 有时也在 Descriptor 块 0x36, 0x48, 0x5A, 0x6C 中
    for (int block = 0; block < 4; ++block)
    {
        int offset = 0x36 + block * 18;
        if (edid[offset] == 0x00 && edid[offset + 1] == 0x00 &&
            edid[offset + 3] == 0xFC)
        {
            QByteArray name((const char*)&edid[offset + 5], 13);
            return QString::fromLatin1(name.trimmed());
        }
    }
    return QString();
}

QList<MonitorData> MonitorInfo::getAllMonitors()
{
    QList<MonitorData> list;

    QList<QScreen*> screens = QGuiApplication::screens();

    HDEVINFO hDevInfo = SetupDiGetClassDevsEx(
        &GUID_DEVCLASS_MONITOR,
        NULL,
        NULL,
        DIGCF_PRESENT,
        NULL,
        NULL,
        NULL
        );

    if (hDevInfo == INVALID_HANDLE_VALUE)
        return list;

    SP_DEVINFO_DATA devInfo;
    devInfo.cbSize = sizeof(SP_DEVINFO_DATA);

    for (int i = 0; i < screens.size(); ++i)
    {
        MonitorData data;
        data.m_scaleFactor = screens[i]->devicePixelRatio();
        // 这个方法无法获取正确的屏幕方向
        // data.m_orientation = screens[i]->primaryOrientation();
        data.m_geometry = screens[i]->geometry();
        data.m_systemName = screens[i]->name();
        if (data.m_systemName.startsWith("\\\\.\\")) {
            data.m_systemName = data.m_systemName.mid(4);
        }

        // 正确获取屏幕方向的方法：
        DEVMODEA dm = { 0 };
        dm.dmSize = sizeof(dm);
        EnumDisplaySettingsA(screens[i]->name().toLatin1().data(), ENUM_CURRENT_SETTINGS, &dm);
        // 0, 1, 2, 3 对应 0°, 90°, 180°, 270°
        switch (dm.dmDisplayOrientation) {
        case DMDO_DEFAULT: data.m_orientation = Qt::LandscapeOrientation; break;
        case DMDO_90:      data.m_orientation = Qt::PortraitOrientation; break;
        case DMDO_180:     data.m_orientation = Qt::InvertedLandscapeOrientation; break;
        case DMDO_270:     data.m_orientation = Qt::InvertedPortraitOrientation; break;
        default:           data.m_orientation = Qt::LandscapeOrientation; break;
        }

        if (SetupDiEnumDeviceInfo(hDevInfo, i, &devInfo))
        {
            HKEY hKey = SetupDiOpenDevRegKey(
                hDevInfo,
                &devInfo,
                DICS_FLAG_GLOBAL,
                0,
                DIREG_DEV,
                KEY_READ
                );

            if (hKey != INVALID_HANDLE_VALUE)
            {
                BYTE edid[256] = {0};
                DWORD edidSize = sizeof(edid);
                if (RegQueryValueExA(hKey, "EDID", NULL, NULL, edid, &edidSize) == ERROR_SUCCESS)
                {
                    data.m_manufacturer = parseManufacturer(edid);
                    data.m_model = parseModelName(edid);
                }
                RegCloseKey(hKey);
            }
        }

        list.append(data);
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
    return list;
}

QString MonitorData::systemName() const
{
    return m_systemName;
}

QString MonitorData::manufacturer() const
{
    return m_manufacturer;
}

QString MonitorData::model() const
{
    return m_model;
}

QRect MonitorData::geometry() const
{
    return m_geometry;
}

qreal MonitorData::scaleFactor() const
{
    return m_scaleFactor;
}

Qt::ScreenOrientation MonitorData::orientation() const
{
    return m_orientation;
}

QPoint MonitorData::toLogical(const QPoint &pos) const
{
    if (m_scaleFactor <= 0.0) {
        return pos;
    }

    QTransform transform;

    // 先缩放
    transform.scale(1.0 / m_scaleFactor, 1.0 / m_scaleFactor);

    // 再旋转
    switch (m_orientation) {
    case Qt::PortraitOrientation:
        transform.rotate(90);
        break;
    case Qt::InvertedLandscapeOrientation:
        transform.rotate(180);
        break;
    case Qt::InvertedPortraitOrientation:
        transform.rotate(270);
        break;
    default:
        break;
    }

    // 用 transform.map(point) 就能得到逻辑坐标
    return transform.map(pos);
}

QRect MonitorData::toLogical(const QRect &rect) const
{
    if (m_scaleFactor <= 0.0)
        return rect;

    QTransform transform;

    // ① 缩放
    transform.scale(1.0 / m_scaleFactor, 1.0 / m_scaleFactor);

    // ② 旋转（按屏幕方向）
    switch (m_orientation) {
    case Qt::PortraitOrientation:
        transform.rotate(90);
        break;
    case Qt::InvertedLandscapeOrientation:
        transform.rotate(180);
        break;
    case Qt::InvertedPortraitOrientation:
        transform.rotate(270);
        break;
    default:
        break; // LandscapeOrientation 不旋转
    }

    // ③ 变换矩形
    QRectF rectF = transform.mapRect(QRectF(rect));

    // ④ 转回整数矩形
    return rectF.toRect();
}
